package com.shelpe.services.sinbad.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.Campaign;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.service.impl.OopKeywordService;
import com.shelpe.services.sinbad.service.simbaproxy.SimbaProxyBaseDto;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/sinbadservice")
public class KeywordsController {

	@Autowired
	private UserRepository userRepository;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private CampaignRepository campaignRepository;
	@Autowired
	private OopKeywordService keywordService;
	
	/**
	 * 关键词出价
	 */
	@RequestMapping(method = RequestMethod.POST, value = "/users/{user_id}/keywords/@pricing")
	@ResponseBody
	public DeferredResult<ListResponse<PricingKeyword>> pricingKeywords(@PathVariable("user_id")final long userID,
			@RequestParam(name="action_types", defaultValue="auto") List<String> actionTypes,
			@RequestBody List<PricingKeyword> keywords){
		log.info("pricingKeywords: userID - {}", userID);
		final long start = System.currentTimeMillis();
		
		final ListResponse<PricingKeyword> ret = new ListResponse<PricingKeyword>();
		final DeferredResult<ListResponse<PricingKeyword>> result = new DeferredResult<ListResponse<PricingKeyword>>();
		ListResponse<PricingKeyword> timeoutRet = new ListResponse<PricingKeyword>();
		timeoutRet.setError(new SimbaProxyBaseDto.Error());
		timeoutRet.getError().setCode(500);
		timeoutRet.getError().setMessage("timeout");
		timeoutRet.getError().setSubCode("timeout");
		timeoutRet.getError().setSubMessage("超时");
		result.onTimeout(new Runnable(){
			@Override
			public void run() {
				log.error("timeout pricingKeywords {}", userID);
			}
		});
		
		if(keywords == null || keywords.size() == 0){
			ret.setStatus(false);
			result.setResult(ret);
			return result;
		}
		
		//纠正一些错误输入
		for(PricingKeyword pkw:keywords){
			if(pkw.getMaxMobilePrice() > 0 && pkw.getMobileIsDefaultPrice() != 0){
				pkw.setMobileIsDefaultPrice(0);
			}
			if(pkw.getMaxMobilePrice() <= 0 && pkw.getMobileIsDefaultPrice() != 1){
				pkw.setMobileIsDefaultPrice(1);
				pkw.setMaxMobilePrice(0);
			}
		}
		
		User user = this.userRepository.findOne(userID);
		Assert.notNull(user, "user_not_found");
		boolean isManual = false;
		boolean isSemiauto = false;
		if(actionTypes != null){
			isManual = actionTypes.indexOf("manual") > -1;
			isSemiauto = actionTypes.indexOf("semiauto") > -1;
		}
		this.keywordService.price(user, keywords, new OopKeywordService.Callback() {
			@Override
			public void call(List<Keyword> savedKeywords) {
				ret.setDatas(new ArrayList<PricingKeyword>());
				if(savedKeywords != null){
					for(Keyword kw: savedKeywords){
						PricingKeyword pkw = new PricingKeyword();
						pkw.setKeywordID(kw.getKeywordId());
						pkw.setWord(kw.getWord());
						pkw.setMatchScope(kw.getMatchscope());
						pkw.setMaxPrice(kw.getMaxPrice());
						pkw.setIsDefaultPrice(0);
						pkw.setMaxMobilePrice(kw.getMaxMobilePrice());
						pkw.setMobileIsDefaultPrice(kw.getMobileIsDefaultPrice());
						ret.getDatas().add(pkw);
					}
				}
				log.info("pricingKeywords costs {} ms", (System.currentTimeMillis() - start));
				ret.setStatus(ret.getDatas().size() > 0);
				result.setResult(ret);
			}
		}, isManual, isSemiauto);
		return result; 
	}
		
	/**
	 * 添加关键词
	 * @param adgroupID
	 * @param keywords
	 * @return
	 */
	@RequestMapping(method = RequestMethod.POST, value = "/adgroups/{adgroupId}/keywords")
	@ResponseBody
	public DeferredResult<ListResponse<PricingKeyword>> addKeywords(@PathVariable("adgroupId")final long adgroupID, 
			@RequestParam(name="action_type", defaultValue="auto") String actionType,
			@RequestBody List<PricingKeyword> keywords){
		log.info("addKeywords: adgroupID - {}", adgroupID);
		final long start = System.currentTimeMillis();
		
		final DeferredResult<ListResponse<PricingKeyword>> result = new DeferredResult<ListResponse<PricingKeyword>>();
		final ListResponse<PricingKeyword> ret = new ListResponse<PricingKeyword>();
		
		ListResponse<PricingKeyword> timeoutRet = new ListResponse<PricingKeyword>();
		timeoutRet.setError(new SimbaProxyBaseDto.Error());
		timeoutRet.getError().setCode(500);
		timeoutRet.getError().setMessage("timeout");
		timeoutRet.getError().setSubCode("timeout");
		timeoutRet.getError().setSubMessage("超时");
		result.onTimeout(new Runnable(){
			@Override
			public void run() {
				log.error("timeout addKeywords {} {}", adgroupID);
			}
		});
		
		if(keywords == null || keywords.size() == 0){
			ret.setStatus(false);
			result.setResult(ret);
			return result;
		}
		
		Adgroup adgroup = adgroupRepository.findOne(adgroupID);
		if(adgroup == null){
			ret.setStatus(false);
			result.setResult(ret);
			return result;
		}
		
		//纠正一些错误输入
		for(PricingKeyword pkw:keywords){
			if(pkw.getMatchScope() <= -1){
				pkw.setMatchScope(4);
			}
			if(pkw.getMobileIsDefaultPrice() > 0 && pkw.getMobileIsDefaultPrice() != 0){
				pkw.setMobileIsDefaultPrice(0);
			}
		}
		
		this.keywordService.add(adgroup, keywords, new OopKeywordService.Callback() {
			@Override
			public void call(List<Keyword> savedKeywords) {
				ret.setDatas(new ArrayList<PricingKeyword>());
				if(savedKeywords != null){
					for(Keyword kw: savedKeywords){
						PricingKeyword pkw = new PricingKeyword();
						pkw.setKeywordID(kw.getKeywordId());
						pkw.setWord(kw.getWord());
						pkw.setMatchScope(kw.getMatchscope());
						pkw.setMaxPrice(kw.getMaxPrice());
						pkw.setIsDefaultPrice(0);
						pkw.setMaxMobilePrice(kw.getMaxMobilePrice());
						pkw.setMobileIsDefaultPrice(kw.getMobileIsDefaultPrice());
						ret.getDatas().add(pkw);
					}
				}
				log.info("addKeywords costs {} ms", (System.currentTimeMillis() - start));
				ret.setStatus(ret.getDatas().size() > 0);
				result.setResult(ret);
			}
		},"manual".equals(actionType));
		return result; 
	}
	
	/**
	 * 删除关键词
	 * @param campaignId
	 * @param keywordIDs
	 * @return
	 */
	@RequestMapping(method = RequestMethod.DELETE, value = "/campaigns/{campaignId}/keywords")
	@ResponseBody
	public DeferredResult<ListResponse<PricingKeyword>> deleteKeywords(@PathVariable("campaignId")long campaignID,
			@RequestParam(name="action_types", defaultValue="auto") List<String> actionTypes,
			@RequestParam("keywordIds") List<Long> keywordIDs){
		log.info("deleteKeywords: campaignID - {}", campaignID);
		final long start = System.currentTimeMillis();
		
		final DeferredResult<ListResponse<PricingKeyword>> result = new DeferredResult<ListResponse<PricingKeyword>>();
		final ListResponse<PricingKeyword> ret = new ListResponse<PricingKeyword>();
		
		ListResponse<PricingKeyword> timeoutRet = new ListResponse<PricingKeyword>();
		timeoutRet.setError(new SimbaProxyBaseDto.Error());
		timeoutRet.getError().setCode(500);
		timeoutRet.getError().setMessage("timeout");
		timeoutRet.getError().setSubCode("timeout");
		timeoutRet.getError().setSubMessage("超时");
		result.onTimeout(new Runnable(){
			@Override
			public void run() {
				log.error("timeout deleteKeywords {} {}", campaignID);
			}
		});
		
		if(keywordIDs == null || keywordIDs.size() == 0){
			ret.setStatus(false);
			result.setResult(ret);
			return result;
		}
		
		Campaign campaign = this.campaignRepository.findOne(campaignID);
		if(campaign == null){
			ret.setStatus(false);
			result.setResult(ret);
			return result;
		}
		
		List<Long> ids = new ArrayList<Long>();
		for(long id:keywordIDs){
			ids.add(id);
		}
		boolean isManual = false;
		boolean isSemiauto = false;
		if(actionTypes != null){
			isManual = actionTypes.indexOf("manual") > -1;
			isSemiauto = actionTypes.indexOf("semiauto") > -1;
		}
		this.keywordService.delete(campaign, ids, new OopKeywordService.Callback() {
			@Override
			public void call(List<Keyword> savedKeywords) {
				ret.setDatas(new ArrayList<PricingKeyword>());
				if(savedKeywords != null){
					for(Keyword kw: savedKeywords){
						PricingKeyword pkw = new PricingKeyword();
						pkw.setKeywordID(kw.getKeywordId());
						pkw.setWord(kw.getWord());
						pkw.setMatchScope(kw.getMatchscope());
						pkw.setMaxPrice(kw.getMaxPrice());
						pkw.setIsDefaultPrice(0);
						pkw.setMaxMobilePrice(kw.getMaxMobilePrice());
						pkw.setMobileIsDefaultPrice(kw.getMobileIsDefaultPrice());
						ret.getDatas().add(pkw);
					}
				}
				log.info("deleteKeywords costs {} ms", (System.currentTimeMillis() - start));
				ret.setStatus(ret.getDatas().size() > 0);
				result.setResult(ret);
			}
		},isManual, isSemiauto);
		
		return result;
	};
	
	@Data
	@JsonInclude(Include.NON_DEFAULT)
	public static class PricingKeyword implements InvokesChunk.Lengthable{
		@JsonProperty("keywordId")
		private long keywordID;
		
		private int matchScope = -1;
		private String word;
		private int maxPrice = -1;
		private int isDefaultPrice = -1;
		private int maxMobilePrice = -1;
		private int mobileIsDefaultPrice = -1;
		@Override
		public int length() {
			int estimateInitialLength = 50;
			if(this.word != null){
				return estimateInitialLength + this.word.length();
			}
			return estimateInitialLength + 20;
		}
	}
	
	@Data
	public static class AdgroupKeywordsDto{
		@JsonProperty("adgroup_id")
		private long adgroupID;
		private List<KeywordDto> keywords;
		
		public void addKeyword(KeywordDto word){
			if(this.keywords == null){
				this.keywords = new ArrayList<KeywordDto>();
			}
			this.keywords.add(word);
		}
	}

	@Data
	public static class KeywordDto {
		@JsonProperty("keyword_id")
		private long keywordID;
		private String word;
		@JsonProperty("max_price")
		private float maxPrice;
		@JsonProperty("max_mobile_price")
		private float maxMobilePrice;
		@JsonProperty("impressions")
		private int impression;//展现量
		@JsonProperty("matchscope")
		private int matchScope;
		private int click;//点击量
		@JsonProperty("ctr")
		private float clickRatio;//点击率
		private float cpc;//平均点击花费
		private float cpm;
		private float cvr;//点击转化率
		@JsonProperty("avgpos")
		private int productRanking;//宝贝排名
		private int qscore;//质量得分
		@JsonProperty("wireless_qscore")
		private int mobileQscore;//移动质量得分
		private float cost;//总花费
		@JsonProperty("sales")
		private float sale;//总金额
		@JsonProperty("total_pay_count")
		private int payCount;//成交笔数
		private float roi;//投入产出比
		@JsonProperty("fav_count")
		private int favCount;//收藏数
		@JsonProperty("fav_count_rate")
		private float favCountRatio;//收藏率
		@JsonProperty("cart_count")
		private int cartCount;//购物车数
		@JsonProperty("cart_count_rate")
		private float cartCountRatio;//购物车率
		@JsonProperty("is_default_price")
		private boolean asDefaultPrice;
		@JsonProperty("is_default_mobile_price")
		private boolean asDefaultMobilePrice;

		private String action;
		@JsonProperty("new_matchscope")
		private int newMatchScope;
		@JsonProperty("new_price")
		private float price;
		@JsonProperty("new_mobile_price")
		private float mobilePrice;
		private int modifiedStatus;
		private boolean matched;
	}
}
